﻿using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using Gumini.JulaDB.DataTypes;
using Gumini.JulaDB.Enums;
using Gumini.JulaDB.Interfaces;

namespace Gumini.JulaDB.Data
{
    /// <summary>
    /// Represents the metadata describing a column in a schema.
    /// </summary>
    [Serializable]
    public class TableColumn : IColumn, ISerializable
    {
        internal TableColumn(string name, DataType type, bool isNullable, int? length)
        {
            this.ColumnName = name;
            this.Type = type;
            this.IsNullable = isNullable;
            this.Length = length;
            this.AllNames = new List<string> { name };
        }

        /// <summary>
        /// The name of the column.
        /// </summary>
        public string ColumnName { get; private set; }
        
        /// <summary>
        /// The type of data stored in the column.
        /// </summary>
        public DataType Type { get; private set; }

        /// <summary>
        /// True when the column allows null values.
        /// </summary>
        public bool IsNullable { get; private set; }

        /// <summary>
        /// Maximum length of data that can be stored in the single field.
        /// </summary>
        public int? Length { get; private set; }

        /// <summary>
        /// All of the names that might refer to this particular column, e.g. 'name', 'person.name', 'p.name'.
        /// </summary>
        public IEnumerable<string> AllNames { get; private set; }

        public override string ToString()
        {
            return String.Format("{0} (type: {1}, nullable: {2}, length: {3})", ColumnName, Type, IsNullable, Length != null ? Length.ToString() : "not specified");
        }

        #region Serialization

        private const string ColumnNameName = "ColumnName";
        private const string TypeName = "Type";
        private const string IsNullableName = "IsNullable";
        private const string LengthName = "Length";
        private const string AllNamesName = "AllNames";

        public TableColumn(SerializationInfo info, StreamingContext context)
        {
            this.ColumnName = (string)info.GetValue(ColumnNameName, typeof(string));
            this.Type = DataType.GetType((JulaDbType)info.GetValue(TypeName, typeof(JulaDbType)));
            this.IsNullable = (bool)info.GetValue(IsNullableName, typeof(bool));
            this.Length = (int?)info.GetValue(LengthName, typeof(int?));
            this.AllNames = (List<string>)info.GetValue(AllNamesName, typeof(List<string>));
        }

        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue(ColumnNameName, this.ColumnName, typeof(string));
            info.AddValue(TypeName, this.Type.Id, typeof(JulaDbType));
            info.AddValue(IsNullableName, this.IsNullable, typeof(bool));
            info.AddValue(LengthName, this.Length, typeof(int?));
            info.AddValue(AllNamesName, this.AllNames, typeof(List<string>));
        }

        #endregion
    }
}
